package org.grayrabbit.cloud.core.server.module;

import java.io.IOException;
import java.util.UUID;

import org.apache.commons.lang.StringUtils;
import org.grayrabbit.cloud.core.Constants;
import org.grayrabbit.cloud.core.biz.BizAbstractModule;
import org.grayrabbit.cloud.core.biz.BizArgument;
import org.grayrabbit.cloud.core.biz.BizResult;
import org.grayrabbit.cloud.core.command.CommandHandlerFactory;
import org.grayrabbit.cloud.core.module.ModuleConstructException;
import org.grayrabbit.cloud.core.module.ModuleException;
import org.grayrabbit.cloud.core.rpc.Argument;
import org.grayrabbit.cloud.core.telnet.TelnetPrintConfiguration;
import org.grayrabbit.cloud.core.telnet.TelnetService;
import org.grayrabbit.cloud.core.telnet.TelnetSessionCallback;
import org.grayrabbit.cloud.core.telnet.TelnetSessionController;
import org.grayrabbit.cloud.core.telnet.TelnetSessionControllerFactory;
import org.grayrabbit.cloud.core.telnet.TelnetSessionState;
import org.grayrabbit.cloud.core.telnet.VT100PrintUtilities;
import org.grayrabbit.cloud.utils.logger.Output;
import org.grayrabbit.cloud.utils.manager.UserManager;
import org.grayrabbit.cloud.utils.manager.UserManager.OperateState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class MonitorModule extends BizAbstractModule {
	private static Logger logger = LoggerFactory.getLogger(MonitorModule.class);
	private static TelnetService telnetService = null;
	private static String passwdPath = null;
	public BizResult submit(Argument arg) throws ModuleException {
		if(passwdPath==null){//启动telnet服务时，初始化passwd文件位置
			passwdPath = this.getProp("passwdpath", true);
		}
		String cmd = ((BizArgument)arg).getCommand();

		if (cmd.equals(Constants.MODULE_COMMAND_SVR_START)) {
			try {
				telnetService.start();
			} catch (IOException e) {
				throw new ModuleException(e);
			}
			return BizResult.TRUE;
		}

		if (cmd.equals(Constants.MODULE_COMMAND_SVR_STOP)) {

			try {
				telnetService.stop();
			} catch (IOException e) {
				throw new ModuleException(e);
			}
			return BizResult.TRUE;
		}

		throw new ModuleException(String.format("Unsupport %s operation", cmd));
	}

	private static class PrintConfiguration implements TelnetPrintConfiguration {
		int rightMargin = 80;

		public String getEOLN() {
			return Constants.NEW_LINE;
		}

		public int getRightMargin() {
			return this.rightMargin;
		}

		public void setRightMargin(int rightMargin) {
			this.rightMargin = rightMargin;
		}
	}

	private static class ControllerFactory implements
			TelnetSessionControllerFactory {

		public TelnetSessionController createSessionController() {
			return new SessionController();
		}
	}

	private static class SessionState implements TelnetSessionState {

		private boolean isActive = true;
		private String username = null;
		private String uid = UUID.randomUUID().toString();
		private int validates = 0;

		public SessionState() {
		}

		public String getUsername() {
			return this.username;
		}

		public void setUsername(String username) {
			this.username = username;
		}

		public void increase() {
			this.validates++;
		}
		public void zero(){
			this.validates = 0;
		}

		public int getValidates() {
			return this.validates;
		}

		public void setSessionActive(boolean isActive) {
			this.isActive = isActive;
		}

		public String getUid() {
			return this.uid;
		}

		public boolean isSessionActive() {
			return this.isActive;
		}
	}

	private static class SessionController extends VT100PrintUtilities
			implements TelnetSessionController, Output {

		private boolean waitingLogin;
		private boolean waitingPassword;
		private boolean waitingOrginPwd = false;
		private boolean waitingNewpwd = false;
		private boolean waitingConfirmPwd = false;
		private String userId;
		private String orginPwd;
		private String newPwd; 
		private String confirmPwd;
		private SessionState controllerState;
		private TelnetSessionCallback controllerListener;
		private TelnetPrintConfiguration printConfiguration;
		
		public String getCurrentUser(){
			return this.controllerState.getUsername();
		}
		public SessionController() {
			this.waitingLogin = true;
			this.controllerState = new SessionState();
		}

		public TelnetSessionState createSessionState() {
			return controllerState;
		}

		public void notifyConnectionEstablished() {
			StringBuffer buffer = new StringBuffer();

			buffer.append(printConfiguration.getEOLN());
			setAttrs(buffer, new byte[][] { RESET, ATTRS_FORE_GREEN, DONE });
			buffer.append("  << ");
			setAttrs(buffer, ATTRS_DEFAULT);
			buffer.append("Server Monitor V1.0");
			setAttrs(buffer, new byte[][] { RESET, ATTRS_FORE_GREEN, DONE });
			buffer.append("  >>");
			setAttrs(buffer, ATTRS_DEFAULT);
			buffer.append(printConfiguration.getEOLN());
			try {
				this.controllerListener.writeln(buffer.toString());
			} catch (IOException e) {
			}
		}

		public String getPrompt(TelnetSessionState _controllerState) {

			if (this.controllerState.getValidates() > 3)
				return "exit";
			if (waitingLogin) {
				StringBuffer buffer = new StringBuffer();
				setAttrs(buffer, new byte[][] { RESET, ATTRS_FORE_GREEN, DONE });
				buffer.append("登录名: ");
				setAttrs(buffer, ATTRS_DEFAULT);
				return buffer.toString();
			} else if (waitingPassword) {
				StringBuffer buffer = new StringBuffer();
				setAttrs(buffer, new byte[][] { RESET, ATTRS_FORE_GREEN, DONE });
				buffer.append("密码: ");
				setAttrs(buffer, ATTRS_DEFAULT);
				return buffer.toString();
			} else if (waitingOrginPwd) {
				StringBuffer buffer = new StringBuffer();
				setAttrs(buffer, new byte[][] { RESET, ATTRS_FORE_GREEN, DONE });
				buffer.append("原密码:");
				setAttrs(buffer, ATTRS_DEFAULT);
				return buffer.toString();
			} else if (waitingNewpwd) {
				StringBuffer buffer = new StringBuffer();
				setAttrs(buffer, new byte[][] { RESET, ATTRS_FORE_GREEN, DONE });
				buffer.append("新密码:");
				setAttrs(buffer, ATTRS_DEFAULT);
				return buffer.toString();
			} else if (waitingConfirmPwd) {
				StringBuffer buffer = new StringBuffer();
				setAttrs(buffer, new byte[][] { RESET, ATTRS_FORE_GREEN, DONE });
				buffer.append("确认密码:");
				setAttrs(buffer, ATTRS_DEFAULT);
				return buffer.toString();
			} else {
				return "[" + controllerState.getUsername() + "@monitor]$ ";
			}
		}

		protected boolean login(TelnetSessionState _controllerState,
				String password) {
			SessionState ss = (SessionState) _controllerState;
			// validate login
			if (validate(ss.getUsername(), password)) {
				try {
					this.controllerListener.writeln("Login successful");
				} catch (IOException e) {

				}
				return true;
			} else
				return false;
		}

		public void setSessionCallback(TelnetSessionCallback controllerListener) {
			this.controllerListener = controllerListener;
		}

		public void setPrintConfiguration(
				TelnetPrintConfiguration printConfiguration) {
			this.printConfiguration = printConfiguration;
		}

		public void notifyNewLine(TelnetSessionState controllerState,
				String currentBuffer, int relOffset) {

			String text = currentBuffer.toString();

			if (waitingLogin) {
				text = text.trim();
				if (text.length() > 0) {
					this.controllerState.setUsername(text);
					this.waitingLogin = false;
					this.waitingPassword = true;
					this.controllerListener.setSuppressOutput(true);
				}
			} else if (waitingPassword) {
				boolean success = login(controllerState, text);
				if (success) {
					this.waitingPassword = false;
					this.controllerListener.setSuppressOutput(false);
					this.controllerState.zero();//归零
				} else {
					this.waitingLogin = true;
					this.waitingPassword = false;
					suppressWriteln("登录失败！");
					if (this.controllerState.getValidates() >= 3){
						((SessionState) controllerState)
						.setSessionActive(false);
					}
					
				}
			}else if(waitingOrginPwd){//原密码，修改密码时使用
				this.waitingOrginPwd = false;
				this.waitingNewpwd = true;
				this.waitingConfirmPwd = false;
				this.orginPwd = text;
				this.controllerListener.setSuppressOutput(true);
			}else if(waitingNewpwd){//新密码
				this.waitingOrginPwd = false;
				this.waitingNewpwd = false;
				this.waitingConfirmPwd = true;
				this.newPwd = text;
				this.controllerListener.setSuppressOutput(true);
			}else if(waitingConfirmPwd){
				this.waitingOrginPwd = false;
				this.waitingNewpwd = false;
				this.waitingConfirmPwd = false;
				this.confirmPwd = text;
				if(orginPwd==null){//新增用户密码
					String usr = userId;
					if(StringUtils.isBlank(userId)){
						usr = this.controllerState.username;
					}
					if(this.newPwd.equals(this.confirmPwd)){
						UserManager um = new UserManager();
						OperateState ost = um.addUser(usr, newPwd);
						if(OperateState.existuser==ost){
							this.confirmPwd = null;
							this.newPwd = null;
							suppressWriteln("该帐号已经存在！");
						}else if(OperateState.fail==ost){
							suppressWriteln("用户创建失败，请重试！");
							resetNew();
						}else if(OperateState.success==ost){
							suppressWriteln("用户创建成功！");
							this.controllerState.zero();//归零
						}else{
							suppressWriteln("未知异常，请重试！");
							resetNew();
						}
					}else{
						suppressWriteln("二次输入密码不一致！");
						resetNew();
					}
				}else{//修改用户密码
					String usr = userId;
					if(StringUtils.isBlank(userId)){
						usr = this.controllerState.username;
					}
					if(this.newPwd.equals(this.confirmPwd)){
						UserManager um = new UserManager();
						OperateState ost = um.modifyPwd(usr, orginPwd,newPwd);
						if(OperateState.errorpwd==ost){
							suppressWriteln("原密码有误！");
							resetOrgin();
						}else if(OperateState.fail==ost){
							suppressWriteln("密码修改失败，请重试！");
							resetOrgin();
						}else if(OperateState.success==ost){
							suppressWriteln("密码修改成功！");
							this.controllerState.zero();//归零
						}else{
							suppressWriteln("未知异常，请重试！");
							resetOrgin();
						}
					}else{
						suppressWriteln("二次输入密码不一致！");
						resetOrgin();
					}
				}
			}else {
				if (text.length() > 0) {
					text = text.trim().toLowerCase();
					char firstChar = text.charAt(0);

					if (firstChar == 'e' && "exit".equals(text)) {
						((SessionState) controllerState)
								.setSessionActive(false);
					} else if (firstChar == 'q' && "quit".equals(text)) {
						((SessionState) controllerState)
								.setSessionActive(false);
					} else {
						CommandHandlerFactory
								.getRemoteCommandHandler(
										((SessionState) controllerState)
												.getUid(),
										this).handler(text);
					}
				}
			}
		}
		//重置建用户时的状态,从输入新密码开始
		private void resetNew(){
			this.confirmPwd = null;
			this.newPwd = null;
			this.waitingNewpwd = true;
			this.controllerListener.setSuppressOutput(true);
			if (this.controllerState.getValidates() >= 3){
				this.controllerListener.setSuppressOutput(false);
				this.waitingNewpwd = false;
				this.controllerState.zero();//归零
			}
		}
		//重置修改密码时状态,从输入原密码开始
		private void resetOrgin(){
			this.orginPwd = null;
			this.confirmPwd = null;
			this.newPwd = null;
			this.waitingOrginPwd = true;
			this.controllerListener.setSuppressOutput(true);
			if (this.controllerState.getValidates() >= 3){
				this.controllerListener.setSuppressOutput(false);
				this.waitingOrginPwd = false;
				this.controllerState.zero();//归零
			}
		}
		private void suppressWriteln(String msg){
			this.controllerListener.setSuppressOutput(false);
			try {
				this.controllerListener.writeln(msg);
			} catch (IOException e) {
			}
			
			this.controllerState.increase();
			
		}
		

		public void notifyDown(TelnetSessionState controllerState,
				String currentBuffer, int relOffset) {

		}

		public void notifyLeft(TelnetSessionState controllerState,
				String currentBuffer, int relOffset) {

		}

		public void notifyRight(TelnetSessionState controllerState,
				String currentBuffer, int relOffset) {

		}

		public void notifyUp(TelnetSessionState controllerState,
				String currentBuffer, int relOffset) {

		}

		public void notifyTab(TelnetSessionState controllerState,
				String currentBuffer, int relOffset) {

		}

		public void notifyControlChar(TelnetSessionState controllerState,
				String currentBuffer, int relOffset, char c) {
			try {
				this.controllerListener.write("^" + c,
						TelnetSessionCallback.OFFSET_UPDATE_LOCK_ALL);
				this.controllerListener.writeNewLine();
			} catch (IOException e) {
			}
		}

		public void writeln(String arg) throws IOException {
			this.controllerListener.writeln(arg);
		}


		public void setCommandState(String usr, boolean orginPwd) {
			this.userId = usr;
			if(orginPwd){
				resetOrgin();
			}else{
				resetNew();
			}
		}
	}

	public void construct(String name) throws ModuleConstructException {
		super.construct(name);

		int port = -1;
		try {
			port = this.getProperty("port",true);
		} catch (Exception e) {
			e.printStackTrace();
		}
		TelnetSessionControllerFactory controllerFactory = new ControllerFactory();
		telnetService = new TelnetService();
		if (port > 0)
			telnetService.setBindPort(port);
		telnetService.setTelnetSessionControllerFactory(controllerFactory);
		telnetService.setPrintConfiguration(new PrintConfiguration());
		try {
			telnetService.start();
		} catch (IOException e) {
			throw new ModuleConstructException(e);
		}

		logger.info("server:>Monitor module start......");
	}

	private  static boolean validate(String usr, String pwd) {
		try {
			UserManager um = new UserManager(passwdPath);
			return um.validate(usr, pwd);
		} catch (IOException e) {
			logger.error("登录验证时出错",e);
		}
		return false;
	}

}
